% emacs: -*- mode: latex; coding: utf-8; -*- 

% Copyright (c) 2007, ChenZaichun
% LISENCE: creative common version 3
%

\documentclass[a4paper,11pt]{article}
\usepackage{CJKutf8}
\author{ChenZaichun}
\usepackage[utf8]{inputenc}   % replace by the encoding you are using
%\usepackage[T1]{fontenc}
\title{设备无关位图}
%\AtBeginDocument{\begin{CJK}{UTF8}{simhei}}
%\AtEndDocument{\closesection{}\end{CJK}}
\pdfoutput=1
\pdfmapfile{=simhei.map}
\parskip=1.618ex
%\parindent=0pt
\usepackage{graphicx}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[colorlinks,linkcolor=blue,
		hyperindex,
                pdfstartview=FitH,
                plainpages=false,
                unicode,
                pdftex]
                {hyperref}
%\usepackage[sf]{titlesec}
%\usepackage{titletoc}
\pdfcompresslevel=9
\usepackage{makeidx,shortvrb,latexsym}

\usepackage{CJKnumb, indentfirst}

\renewcommand{\arraystretch}{1.2}
\usepackage{tabularx}
\usepackage{booktabs,longtable}

\lstset{language=C++,%
  tabsize=4,%
  keepspaces=true,%
  breakindent=22pt,% 
  numbers=left,%
  stepnumber=1,%
  numberstyle=\tiny,%
  basicstyle=\footnotesize,%
  showspaces=false,%
  frame=shadowbox,%
  rulesepcolor=\color{red!20!green!20!blue!20},%
  keywordstyle=\color{blue!70},%
  commentstyle=\color{red!50!green!50!blue!50},%
  flexiblecolumns=true,%
  breaklines=true,%
  breakautoindent=true,%
  breakindent=4em,%
  escapeinside={(*@}{@*)},%
  xleftmargin=2em,%
  xrightmargin=2em,% 
  aboveskip=1em,%
  frameround=tttt,%
  nolol=true,%
  showstringspaces=false,%
  escapebegin=\begin{CJK*}{UTF8}{simhei},%
    escapeend=\end{CJK*},%
  texcl=true% 这句很重要，可将注释环境修改成中文环境！
} 

% \newcommand{itemss} {
%   \setlength{\itemsep}{0ex}
%   \setlength{\leftmargin}{0cm}
%   \setlength{\rightmargin{0cm}
% }

% \lstnewenvironment{cpp}{%
%   \lstset{language=c++,showspaces=true,breaklines=true,%
%   basicstyle=\ttfamily,%
%   escapebegin=\begin{CJK*}{UTF8}{simhei},escapeend=\end{CJK*},texcl=true% 这句很重要，可将注释环境修改成中文环境！
%   }}{}

\begin{document}
\begin{CJK}{UTF8}{simhei}
%\CJKtilde
\CJKindent

\maketitle
\begin{center}
$Id: dib.tex 8 2007-12-01 13:12:21Z ChenZaichun $
\end{center}

\tableofcontents

\section{简介}

位图一共有两种类型，即：设备相关位图（DDB）和设备无关位图（DIB）。DDB位图在早期的Windows系统（Windows 3.0以前）中是很普遍的，事实上它也是唯一的。然而，随着显示器制造技术的进步，以及显示设备的多样化，DDB位图的一些固有的问题开始浮现出来了，象BitBlt()这种函数就是基于DDB位图的。比如，它不能够存储（或者说获取）创建这张图片的原始设备的分辩率，这样，应用程序就不能快速的判断客户机的显示设备是否适合显示这张图片。为了解决这一难题，微软创建了DIB位图格式。

BMP文件是Windows保存图像的一种通用文件格式，在数字图像处理方面占有重要的地位。BMP文件中保存的图像数据是一种DIB(Device-Independent Bitmap，即设备无关位图)，DIB是标准的Windows位图格式，它自带颜色信息，因此调色板管理非常容易。

\section{BMP文件的结构}
%\label{sec:结构}

DIB位图包含下列的颜色和尺寸信息：
\begin{itemize}
\item{原始设备（即创建图片的设备）的颜色格式}
\item{原始设备的分辩率}
\item{原始设备的调色板}
\item{一个位数组，由红、绿、蓝（RGB）三个值代表一个像素}
\item{一个数组压缩标志，用于表明数据的压缩方案（如果需要的话）}
\end{itemize}

以上这些信息保存在\textcolor{blue}{BITMAPINFO}结构中，而该结构由一下几部分组成：BITMAPINFOHEADER结构和两个或更多个RGBQUAD。

BITMAPINFOHEADER结构所包含的成员表明了图像的尺寸、原始设备的颜色格式、以及数据压缩方案等信息。RGBQUAD结构标识了像素所用到的颜色数据。

\begin{tabular}[t]{@{}ccc@{}}
\hline
位图文件的组成 & 结构名称 & 符号 \\
\hline
位图文件头 & BITMAPFILEHEADER & bmfh \\
位图信息头 & BITMAPINFOHEADER & bmih \\
彩色表 & RGBQUAD & aColors[] \\
图象数据阵列字节 & BYTE & aBitmapBits[]\\
\hline
\end{tabular}

\subsection{位图文件形式化结构}

\begin{tiny}
%\begin{longtable}[c]{llllX}
\begin{tabularx}{\textwidth}{p{1em}p{3em}lp{4em}X}
\hline
 & 偏移量 & 域的名称 & 大小 & 内容 \\
\hline　 
图象文件头 & 0000h & 文件标识 & 2 bytes & 两字节的内容用来识别位图的类型:
\begin{itemize}
\item{‘BM’ ：Windows 3.1x, 95, NT, \dots}
\item{‘BA’ ：OS/2 Bitmap Array}
\item{‘CI’ ：OS/2 Color Icon }
\item{‘CP’ ：OS/2 Color Pointer}
\item{‘IC’ ：OS/2 Icon }
\item{‘PT’ ：OS/2 Pointer }
\item{注：因为OS/2系统并没有被普及开，所以在编程时，你只需判断第一个标识“BM”就行。}
\end{itemize}\\
\hline
 & 0002h & File Size & 1 dword &	用字节表示的整个文件的大小 \\
 & 0006h & Reserved & 1 dword& 保留，必须设置为0\\
 & 000Ah & Bitmap Data Offset & 1 dword & 从文件开始到位图数据开始之间的数据(bitmap data)之间的偏移量\\
\hline
位图信息头 & 000Eh & Bitmap Header Size & 1 dword & 位图信息头(Bitmap Info Header)的长度，用来描述位图的颜色、压缩方法等。下面的长度表示:
\begin{itemize}
\item{28h - Windows 3.1x, 95, NT, \dots}
\item{0Ch - OS/2 1.x}
\item{F0h - OS/2 2.x}
\item{注：在Windows95、98、2000等操作系统中，位图信息头的长度并不一定是28h，因为微软已经制定出了新的BMP文件格式，其中的信息头结构变化比较大，长度加长。所以最好不要直接使用常数28h，而是应该从具体的文件中读取这个值。这样才能确保程序的兼容性。}
\end{itemize}\\
\hline
 & 0012h & Width & 1 dword & 位图的宽度，以象素为单位\\
\hline
 & 0016h & Height & 1 dword & 位图的高度，以象素为单位\\
\hline
 & 001Ah & Planes & 1 word & 位图的位面数（注：该值将总是1）\\
\hline
 & 001Ch & Bits Per Pixel & 1 word & 每个象素的位数：
\begin{itemize}
\item{1 - 单色位图（实际上可有两种颜色，缺省情况下是黑色和白色。你可以自己定义这两种颜色）}
\item{4 - 16 色位图}
\item{8 - 256 色位图}
\item{16 - 16bit 高彩色位图}
\item{24 - 24bit 真彩色位图}
\item{32 - 32bit 增强型真彩色位图}
\end{itemize}\\
\hline
 & 001Eh & Compression & 1 dword & 压缩说明：
\begin{itemize}
\item{0 - 不压缩 (使用BI_RGB表示)}
\item{1 - RLE 8-使用8位RLE压缩方式(用BI_RLE8表示)}
\item{2 - RLE 4-使用4位RLE压缩方式(用BI_RLE4表示)}
\item{3 - Bitfields-位域存放方式(用BI_BITFIELDS表示)}
\end{itemize}\\
\hline
 & 0022h & Bitmap Data Size & 1 dword & 用字节数表示的位图数据的大小。该数必须是4的倍数\\
\hline
 & 0026h & HResolution & 1 dword & 用象素/米表示的水平分辨率\\
\hline
 & 002Ah & VResolution & 1 dword & 用象素/米表示的垂直分辨率\\
\hline
 & 002Eh & Colors & 1 dword & 位图使用的颜色数。如8-比特/象素表示为100h或者 256.\\
\hline
 & 0032h & Important Colors & 1 dword & 指定重要的颜色数。当该域的值等于颜色数时（或者等于0时），表示所有颜色都一样重要\\
\hline
调色板数据 & 根据BMP版本的不同而不同 & Palette &N * 4 byte & 调色板规范。对于调色板中的每个表项，这4个字节用下述方法来描述RGB的值： 
\begin{itemize}
\item{1字节用于蓝色分量}
\item{1字节用于绿色分量}
\item{1字节用于红色分量}
\item{1字节用于填充符(设置为0)}
\end{itemize}\\
\hline
图象数据 & 根据BMP版本及调色板尺寸的不同而不同 & Bitmap Data & xxx bytes & 该域的大小取决于压缩方法及图像的尺寸和图像的位深度，它包含所有的位图数据字节，这些数据可能是彩色调色板的索引号，也可能是实际的RGB值，这将根据图像信息头中的位深度值来决定。\\
\end{tabularx}
%\end{longtable}
\end{tiny}

\section{写位图}

写bitmap的一般过程：
\begin{enumerate}
\item{申明BITMAPFILEHEADER，并清空该结构}
  \begin{lstlisting}
BITMAPFILEHEADER bfh;
memset( &bfh, 0, sizeof( bfh ) );
  \end{lstlisting}
\item{初始化该结构}
  \begin{lstlisting}
bfn.bfType = 'MB';			// Bitmap
//file size，cbBuffer is the data size
bfn.bfSize = sizeof(bfn) + cbBuffer + sizeof(BITMAPINFOHEADER);
//offset of the data
bfn.bfOffBits = sizeof(BITMAPINFORHEADER) + sizeof(BITMAPFILEHEADER);
  \end{lstlisting}
\item{将bfn写入文件}
\item{申明BITMAPINFOHEADER，并清空该结构}
  \begin{lstlisting}
BITMAPINFOHEADER bih;
memset( &bih, 0, sizeof( bih ) );
  \end{lstlisting}
\item{初始化该结构}
  \begin{lstlisting}
bih.biSize = sizeof( bih );
bih.biWidth = biWidth;				//width
bih.biHeight = biHeight;			//height
bih.biPlanes = biPlanes;			//planes
bih.biBitCount = biBitCount;		//bpp
  \end{lstlisting}
\item{将bih写入文件}
\item{最后写入数据就行了}
\end{enumerate}

\section{读位图}
\begin{lstlisting}[keywordstyle=\color{black}]{}
If open Bitmap file
Read two bytes (type) and if different than 0x4D42 stop
Ignore eight bytes
Read four bytes (start of image data)
Ignore four bytes
Read four bytes (width of bitmap)
Read four bytes (height of bitmap)
Ignore two bytes
Read two bytes (bit count of bitmap) and if different than 24 stop
Read four bytes (compression of bitmap) and if different than BI_RGB stop
Move to start of image data
Allocate memory for image data (3(one byte for red, other for
green other for blue) * ImageWidth * ImageHeight)
Read (3 * ImageWidth * ImageHeight) bytes from file to buffer
Swap the red and blue components of buffer
If ImageHeight is negative
Flip the buffer lines
End if
Close file
\end{lstlisting}

%%% \begin{figure}%[!hbp]
%%% \includegraphics[width=\textwidth]{fat.jpg}
%%% \caption{WinHex打开FAT32格式分区 图示} \label{winhex}
%%% \end{figure}

%\begin{figure}[!hbp]
%\begin{lstlisting}
% [language={[ANSI]C++}, 
%   keywordstyle=\color{blue!70}, 
%   commentstyle=\color{red!50!blue!50!green!50}, 
%   escapeinside=``, 
%   basicstyle=\small]
% \begin{lstlisting}{}[language=C++]
% int main(int argc, char ** argv)
% {
%     /* print hello word */
%     printf("Hello world!\n");

%     return 0;
% }
% \end{lstlisting}
% \caption{Hello world} \label{helloworldsrc}
% \end{figure}

% \begin{lstlisting}[language=C++,float,
%   caption={Hello world},
%   label=hsrc]
% int main(int argc, char ** argv)
% {
%     /* print hello word */
%     printf("Hello world!\n");(*@\label{hellosrc}@*)

%     return 0;
% }
% \end{lstlisting}

% %\lstlistoflistings
% see Listing \ref{hsrc} Line \ref{hellosrc}.

\end{CJK}
\end{document}

